package com.sy.simpleegg.serialport.whmandroid.cash

import android.util.Log
import com.sy.simpleegg.config.Config
import com.sy.simpleegg.constant.Constant
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.util.CommonUtil
import com.sy.simpleegg.util.Preference
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.Timer
import java.util.TimerTask

class CashParser(
    private val coroutineScope: CoroutineScope,
    val callback: CashParseCallback
) {

    val TAG = javaClass.simpleName

    private var checkJob: Job? = null

    private var testJob: Job? = null

    /**
     * 通道一
     */
    private val CHANNEL_1 = "818F40"

    /**
     * 通道二
     */
    private val CHANNEL_2 = "818F41"

    /**
     * 通道三
     */
    private val CHANNEL_3 = "818F42"

    /**
     * 通道四
     */
    private val CHANNEL_4 = "818F43"

    /**
     * 通道五
     */
    private val CHANNEL_5 = "818F44"

    /**
     * 通道六
     */
    private val CHANNEL_6 = "818F45"
    /**
     * 通道七
     */
    private val CHANNEL_7 = "818F46"
    /**
     * 通道八
     */
    private val CHANNEL_8 = "818F47"
    /**
     * 通道九
     */
    private val CHANNEL_9 = "818F48"
    /**
     * 通道十
     */
    private val CHANNEL_10 = "818F49"

    /**
     * 初始化或者重置
     */
    private val INIT = "808F"

    /**
     * 进钞
     */
    private val IN_MONEY = "81"

    /**
     * 纸钞前缀
     */
    private val MONEY_HEAD_1 = "3D"

    /**
     * 纸钞前缀
     */
    private val MONEY_HEAD_2 = "8F"

    /**
     * 接收完毕
     */
    private val SAVE_MONEY_SUCCESS = "10"

    /**
     * 接收失败
     */
    private val SAVE_MONEY_FAILE = "11"

    /**
     * 结束
     */
    private val FINISH = "292F"

    /**
     * 纸钞校验标记
     */
    private val FLAG_MONEY = "3D"

    /**
     * 使能
     */
    private val ENABLE = "3E"

    /**
     * 禁能
     */
    private val DISABLE = "5E"

    /**
     * 拒钞
     */
    private val REJECTION = "0F"

    /**
     * 暂存
     */
    private val STAGING = "18"

    /**
     * 检测状态
     */
    private val CHECK = "0C"

    /**
     * 重置
     */
    private val RESET = "30"

    /**
     * 进钞 或者 初始化通讯
     */
    private val IN_CASH = "02"

    private var totalMoney = 0L
    private var checkMoney = 0L

    /**
     * 进钞后，是否检测面值
     */
    private var checkCash = false

    /**
     * 纸钞前缀
     */
    private var head = ""

    private var isInit = false

    private var recFinishCount = 0

    private var isClose = true

    private var isSaveMoney = false

    private var timer: Timer? = null

    private var rec3E = false
    private var send3ECount = 0

    /**
     * 国家地区
     */
    private var country: Int by Preference(Constant.SETTING_COUNTRY, Config.DEFAULT_COUNTRY_CODE)

    private var channelParams: String by Preference(Constant.SETTING_CASH_CHANNEL_CONFIG, CommonUtil.getChannelMode(country))

    private var channel1Param = -1L
    private var channel2Param = -1L
    private var channel3Param = -1L
    private var channel4Param = -1L
    private var channel5Param = -1L
    private var channel6Param = -1L
    private var channel7Param = -1L
    private var channel8Param = -1L
    private var channel9Param = -1L
    private var channel10Param = -1L
    private var channelArea = ""

    fun onDataRec(dataHex: String){
        try {
            if (dataHex.isEmpty()){
                return
            }

            var str = dataHex
            logFile("收到纸钞数据:$str")
            if (str == "3E"){
                rec3E = true
                send3ECount = 0
            }

            if (FINISH == str) {
                checkCash = false
                head = ""
                recFinishCount++
                if (recFinishCount >= 3) {
                    logFile("纸钞机异常，进钞没有校验数据，只收到292F，需要发送重置指令，重新进钞")
                    //重新开始进钞
                    disableOnly()
                    isClose = false
                    val timer = Timer()
                    timer.schedule(object : TimerTask() {
                        override fun run() {
                            if (!isClose) {
                                enableOnly()
                            }
                        }
                    }, 500)
                }
                return
            } else {
                recFinishCount = 0
            }

            if (str.contains("818F")) {
                checkCash = true
            }
            logFile("checkCash:$checkCash isSaveMoney:$isSaveMoney")

            /**
             * 发送接收纸钞后，收到纸钞数据则执行此代码
             */
            if (isSaveMoney) {
                //收到暂存指令响应
                if ("2A" == str) {
                    logFile("允许进钞指令发送后收到暂存响应指令")
                    return
                }
//                if (timer != null) {
//                    timer!!.cancel()
//                    timer = null
//                }
                delayToCheckRec10(false)
                if (SAVE_MONEY_SUCCESS == str) {
                    isSaveMoney = false
                    checkCash = false
                    totalMoney += checkMoney
                    Log.d(TAG, "纸钞机一共收到 $totalMoney 元")
                    callback.getMoney(checkMoney, totalMoney)
                } else if (SAVE_MONEY_FAILE == str) {
                    isSaveMoney = false
                    logFile("纸钞接收失败:$checkCash")
                    checkCash = false
                }
                return
            }

            if (checkCash) {
                Log.d(TAG, "纸钞数据长度:" + str.length)
                if (str.length == 4 || str.length == 6) {
                    str = head + str
                    logFile("收到纸钞最终识别数据:$str")
                    if (isClose) {
                        logFile("纸钞机禁能指令发送后收到纸钞识别数据:$str")
                        rejection()
                        return
                    }
                    when (str) {
                        CHANNEL_1 -> {
                            checkMoney = channel1Param/100
                            Log.d(TAG, "收到通道1纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_2 -> {
                            checkMoney = channel2Param/100
                            Log.d(TAG, "收到通道2纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_3 -> {
                            checkMoney = channel3Param/100
                            Log.d(TAG, "收到通道3纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_4 -> {
                            checkMoney = channel4Param/100
                            Log.d(TAG, "收到通道4纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_5 -> {
                            checkMoney = channel5Param/100
                            Log.d(TAG, "收到通道5纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_6 -> {
                            checkMoney = channel6Param/100
                            Log.d(TAG, "收到通道6纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_7 -> {
                            checkMoney = channel7Param/100
                            Log.d(TAG, "收到通道7纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_8 -> {
                            checkMoney = channel8Param/100
                            Log.d(TAG, "收到通道8纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_9 -> {
                            checkMoney = channel9Param/100
                            Log.d(TAG, "收到通道9纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CHANNEL_10 -> {
                            checkMoney = channel10Param/100
                            Log.d(TAG, "收到通道10纸钞面额：$checkMoney")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        else -> {Log.d(TAG, "收到未定义通道面额")}
                    }
                    return
                } else if (MONEY_HEAD_1 == str) {
                    head = head + str
                    Log.d(TAG, "纸钞 head1=$head")
                    return
                } else if (MONEY_HEAD_2 == str) {
                    head = head + str
                    Log.d(TAG, "纸钞 head2=$head")
                    return
                } else if (IN_MONEY == str) {
                    head = str + head
                    Log.d(TAG, "纸钞 head3=$head")
                    return
                }
            }

            //指令处理

            //指令处理
            if (INIT == str) {
                //初始化通讯指令，安卓板收到后需要发送 02 响应
                initBanknote()
            } else if (IN_MONEY == str) {
                //进钞后，需要校验进钞面值
                checkCash = true
                checkMoney = 0
                head = IN_MONEY
                Log.d(TAG, "纸钞 head4=$head")
            } else if (MONEY_HEAD_1 == str) {
                checkCash = true
                checkMoney = 0
                head = MONEY_HEAD_1
                Log.d(TAG, "纸钞 head5=$head")
            } else if (MONEY_HEAD_2 == str) {
                checkCash = true
                checkMoney = 0
                head = MONEY_HEAD_2
                Log.d(TAG, "纸钞 head6=$head")
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("纸钞机处理响应数据异常：${e.message}")
        }
    }

    private fun setChannelParam(){
        channelParams.split(";").let {
            val area = it[1]
            val config = it[0]

            val channelItems = config.split(",")
            channel1Param = channelItems[0].toLong()
            channel2Param = channelItems[1].toLong()
            channel3Param = channelItems[2].toLong()
            channel4Param = channelItems[3].toLong()
            channel5Param = channelItems[4].toLong()
            channel6Param = channelItems[5].toLong()
            channel7Param = channelItems[6].toLong()
            channel8Param = channelItems[7].toLong()
            channel9Param = channelItems[8].toLong()
            channel10Param = channelItems[9].toLong()
            channelArea = area
        }
        logFile("通道配置：channel1=$channel1Param channel2=$channel2Param channel3=$channel3Param channel4=$channel4Param channel5=$channel5Param channel6=$channel6Param channel7=$channel7Param channel8=$channel8Param channel9=$channel9Param channel10=$channel10Param channelArea=$channelArea")
    }

    /**
     * 初始化通讯
     */
    private fun initBanknote() {
        if (!isInit) {
            isInit = true
            val timer = Timer()
            timer.schedule(object : TimerTask() {
                override fun run() {
                    logFile("发送到纸钞机：$IN_CASH 初始化通讯")
                    sendHexStr(IN_CASH)
                    try {
                        Thread.sleep(200)
                    } catch (e: InterruptedException) {
                        e.printStackTrace()
                    }
                    disable()
                    isInit = false
                }
            }, 200)
        }
    }

    fun startInMoney(isStart: Boolean) {
        if (isStart) {
            setChannelParam()
            enable()
        } else {
            disable()
        }
    }

    fun canSaveMoney(isSave: Boolean) {
        if (isSave) {
            saveMoney()
        } else {
            rejection()
        }
    }

    /**
     * 接收纸钞
     */
    private fun saveMoney() {
        try {
            isSaveMoney = true
//            if (timer != null) {
//                timer!!.cancel()
//                timer = null
//            }
//            timer = Timer()
//            timer!!.schedule(object : TimerTask() {
//                override fun run() {
//                    logFile("纸钞机发送02指令后未收到响应数据")
//                    isSaveMoney = false
//                }
//            }, 4000)
            delayToCheckRec10(true)
            logFile("发送到纸钞机：$IN_CASH 允许进钞")
            sendHexStr(IN_CASH)
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("接收纸钞处理异常：" + e.message)
        }
    }

    private fun delayToCheckRec10(open: Boolean){
        checkJob?.cancel()
        if (open){
            checkJob = coroutineScope.launch(Dispatchers.IO) {
                delay(5000)
                logFile("纸钞机发送02指令后未收到响应数据")
                isSaveMoney = false
            }
        }
    }

    fun isSavingMoney(): Boolean {
        return isSaveMoney
    }

    private fun sendHexStr(dataHexStr: String){
        try {
            callback.sendData(dataHexStr)
//            val sendTimer = Timer()
//            sendTimer.schedule(object : TimerTask() {
//                override fun run() {
//                    callback.sendData(dataHexStr)
//                }
//            }, 500)
        }catch (e: Exception){
            logFile("纸钞机 sendByte 发送指令异常：${e.message}")
        }
    }

    private fun disableOnly() {
        logFile("发送到纸钞机-：$DISABLE 禁能")
        sendHexStr(DISABLE)
    }

    private fun enableOnly(){
        logFile("发送到纸钞机-：$ENABLE 使能")
        sendHexStr(ENABLE)
    }

    /**
     * 拒收
     */
    private fun rejection(){
        logFile("发送到纸钞机：$REJECTION 拒收")
        sendHexStr(REJECTION)
    }

    /**
     * 暂存
     */
    private fun staging() {
        logFile("发送到纸钞机：$STAGING 暂存")
        sendHexStr(STAGING)
    }

    /**
     * 使能
     */
    private fun enable() {
        isClose = false
        recFinishCount = 0
        logFile("发送到纸钞机：$ENABLE 使能")
        rec3E = false
        sendHexStr(ENABLE)
        testJob?.cancel()
        testJob = coroutineScope.launch(Dispatchers.IO) {
            coroutineScope.launch(Dispatchers.IO) {
                delay(1000)
                if (!rec3E) {
                    logFile("纸钞机发送3E指令后未收到响应数据")
                    send3ECount ++
                    if (send3ECount < 3){
                        enable()
                    }else{
                        send3ECount = 0
                    }
                }
            }
        }
    }

    /**
     * 禁能
     */
    private fun disable() {
        isClose = true
        if (!rec3E){
            send3ECount = 0
            rec3E = true
        }
        totalMoney = 0
        logFile("发送到纸钞机：$DISABLE 禁能")
        sendHexStr(DISABLE)
    }

    private fun checkMoneyGetCoin(money: Long, checkMoney: Long) {
        staging()
        //收到纸钞后，检查总金额出币数量是否超过剩余币数
        callback.recieveMoney(money, checkMoney)
    }

    interface CashParseCallback{

        fun sendData(dataHex: String)

        /**
         * 进钞
         * @param checkMoney 当前进钞的面额
         * @param totalMoney 总进钞面额
         */
        fun getMoney(checkMoney: Long, totalMoney: Long)

        /**
         * 校验金额是否超过剩余币数或其他逻辑，根据继承者处理进钞或拒绝
         * @param tempMoney
         * @param checkMoney
         */
        fun recieveMoney(tempMoney: Long, checkMoney: Long)
    }
}